package com.quanxiaoha.xiaohashu.user.biz.runner;


import cn.hutool.core.collection.CollUtil;
import com.quanxiaoha.framework.common.util.JsonUtils;
import com.quanxiaoha.xiaohashu.user.biz.constant.RedisKeyConstants;
import com.quanxiaoha.xiaohashu.user.biz.domain.dataobject.PermissionDO;
import com.quanxiaoha.xiaohashu.user.biz.domain.dataobject.RoleDO;
import com.quanxiaoha.xiaohashu.user.biz.domain.dataobject.RolePermissionDO;
import com.quanxiaoha.xiaohashu.user.biz.domain.mapper.PermissionDOMapper;
import com.quanxiaoha.xiaohashu.user.biz.domain.mapper.RoleDOMapper;
import com.quanxiaoha.xiaohashu.user.biz.domain.mapper.RolePermissionDOMapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Component
@Slf4j
public class PushRolePermissions2RedisRunner implements ApplicationRunner {
    
    @Resource
    private RoleDOMapper roleDOMapper;
    
    @Resource
    private RolePermissionDOMapper rolePermissionDOMapper;

    @Resource
    private PermissionDOMapper permissionDOMapper;

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    // 权限同步标记 Key
    private static final String PUSH_PERMISSION_FLAG = "push.permission.flag";

    @Override
    public void run(ApplicationArguments args) {
        log.info("==> 服务启动，开始同步角色权限数据到 Redis 中...");
        try{
            boolean canPushed = redisTemplate.opsForValue().setIfAbsent(PUSH_PERMISSION_FLAG, "1", 1, TimeUnit.DAYS);

            // 如果无法同步权限数据
            if (!canPushed) {
                log.warn("==> 角色权限数据已经同步至 Redis 中，不再同步...");
                return;
            }

            //查询所有角色ID
            List<RoleDO> roleDOS = roleDOMapper.selectEnabledList();
            if(CollUtil.isNotEmpty(roleDOS)){
                List<Long> idList = roleDOS.stream().map(roleDO -> roleDO.getId()).toList();
                List<RolePermissionDO> rolePermissionDOS = rolePermissionDOMapper.selectByRoleIds(idList);


                //根据所有角色ID查询所有角色权限id
                Map<Long, List<Long>> roleIdPermissionIdsMap = rolePermissionDOS.stream().collect(Collectors.groupingBy(RolePermissionDO::getRoleId,
                        Collectors.mapping(RolePermissionDO::getPermissionId, Collectors.toList())));


                //查询已经启用的权限
                List<PermissionDO> permissionDOS = permissionDOMapper.selectAppEnabledList();
                //把权限id提取出来对应do
                Map<Long, PermissionDO> permissionIdDOMap = permissionDOS.stream().collect(Collectors.toMap(PermissionDO::getId, permissionDO -> permissionDO));
                //开始制作角色id对应权限关系表
                Map<String, List<String>> roleIdPermissionDoMap = new HashMap<>();


                roleDOS.forEach(roleDO -> {
                    Long roleId = roleDO.getId();
                    //当前角色key
                    String roleKey = roleDO.getRoleKey();
                    //当前角色对应权限集合
                    List<Long> roles = roleIdPermissionIdsMap.get(roleId);
                    if(CollUtil.isNotEmpty(roles)){
                        List<String> permissionKeys= new ArrayList<>();
                        roles.forEach(id -> {
                            PermissionDO permissionDO = permissionIdDOMap.get(id);
                            if(Objects.nonNull(permissionDO)){
                                permissionKeys.add(permissionDO.getPermissionKey());
                            }
                        });
                        roleIdPermissionDoMap.put(roleKey, permissionKeys);
                    }
                });

                //存入redis
                roleIdPermissionDoMap.forEach((roleKey, permission) -> {
                    String rolePermissionsKey = RedisKeyConstants.buildRolePermissionsKey(roleKey);
                    redisTemplate.opsForValue().set(rolePermissionsKey, JsonUtils.toJsonString(permission));
                });

                log.info("==> 服务启动，成功同步角色权限数据到 Redis 中...");
            }

        } catch (Exception e) {
            log.error("==> 同步角色权限数据到 Redis 中失败: ", e);
        }
    }
}
